﻿using System.Collections.Concurrent;
using System.Net.Sockets;
using System.Net;
using System.Text;

namespace TaskCompletionSourceServer2
{
    internal class Program
    {
        static void Main(string[] args)
        {
            StartSocketServer();

            Console.WriteLine("服务端Ready");
            Console.ReadLine();
        }

        static void StartSocketServer()
        {
            IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, 3001);
            Socket serverSocket = new Socket(ipEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            serverSocket.Bind(ipEndPoint);
            serverSocket.Listen(5000);
            Thread thread = new Thread(new ThreadStart(delegate ()
            {
                while (true)
                {
                    Socket client = null;

                    try
                    {
                        client = serverSocket.Accept();
                        client.SendTimeout = 20000;
                        client.ReceiveTimeout = 20000;
                        client.SendBufferSize = 10240;
                        client.ReceiveBufferSize = 10240;
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.ToString());
                        Thread.Sleep(1);
                        continue;
                    }

                    if (client == null) continue;

                    try
                    {
                        byte[] buffer = new byte[10240];
                        SocketAsyncEventArgs args = new SocketAsyncEventArgs();
                        args.SetBuffer(buffer, 0, buffer.Length);
                        args.Completed += (s, e) =>
                        {
                            if (s == null) return;

                            ReceiveData(client, e);
                        };
                        client.ReceiveAsync(args);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.ToString());
                    }
                }
            }));
            thread.IsBackground = true;
            thread.Start();
        }

        static async void ReceiveData(Socket socket, SocketAsyncEventArgs e)
        {
            if (e.BytesTransferred == 0)
            {
                // Console.WriteLine("e.BytesTransferred=0");
                socket.Close();
                return;
            }
            if (e.Buffer == null)
            {
                Console.WriteLine("e.Buffer=null");
                return;
            }
            if (e.BytesTransferred <= 12)
            {
                if (!socket.ReceiveAsync(e)) ReceiveData(socket, e);
            }

            await Task.Delay(10);

            byte[] buffer = new byte[e.BytesTransferred];
            CopyTo(e.Buffer, buffer, 0, 0, e.BytesTransferred);
            ProcessData(socket, e, buffer);
            socket.Close();
        }

        static void ProcessData(Socket socket, SocketAsyncEventArgs e, byte[] buffer)
        {
            byte[] longByteArr = new byte[8];
            byte[] msgLengthByteArr = new byte[4];
            CopyTo(buffer, longByteArr, 0, 0, 8);
            CopyTo(buffer, msgLengthByteArr, 8, 0, 4);
            long index = BitConverter.ToInt64(longByteArr);
            int msgLength = BitConverter.ToInt32(msgLengthByteArr);

            if (e != null && e.BytesTransferred < 12 + msgLength)
            {
                if (!socket.ReceiveAsync(e)) ReceiveData(socket, e);
            }

            string msg = Encoding.UTF8.GetString(buffer, 12, msgLength);
            Console.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss} {msg}");

            byte[] indexByteArr = BitConverter.GetBytes(index);
            byte[] msgByteArr = Encoding.UTF8.GetBytes($"客户端你好_{index}");
            int length = msgByteArr.Length;
            byte[] lengthByteArr = BitConverter.GetBytes(length);
            var bytes = new ArraySegment<byte>(indexByteArr.Concat(lengthByteArr).Concat(msgByteArr).ToArray());
            socket.Send(bytes, SocketFlags.None);
        }

        static void CopyTo(byte[] bArrSource, byte[] bArrTarget, int sourceIndex, int targetIndex, int length)
        {
            for (int i = 0; i < length; i++)
            {
                if (targetIndex + i < bArrTarget.Length && sourceIndex + i < bArrSource.Length)
                {
                    bArrTarget[targetIndex + i] = bArrSource[sourceIndex + i];
                }
            }
        }
    }
}
